import java.math.BigInteger;
import java.util.*;

/**
 * @author anan
 * @create 2022-03-24 16:57
 */
public class Main {
    public final static String url = "Z:\\study\\华为软挑战\\线下调试数据\\data\\";
    public final static String urlOut = "Z:\\study\\华为软挑战\\线下调试数据\\output\\solution.txt";
    public static Map<String, Integer> notOcupy = new HashMap<>();

    public static void main(String[] args) {
        MyFile myFile = new MyFile();
        MyFileReader.readAll(myFile, url);

        List<String> clientId = myFile.getClientId();
        List<Map<String, Integer>> demand = myFile.getDemand();
        List<String> edgeNodeId = myFile.getEdgeNodeId();
        Map<String, Integer> siteBandwidth = myFile.getSiteBandwidth();
        Map<String, Integer> qos = myFile.getQos();
        Integer qosConStraint = myFile.getQosConStraint();

        List<Map<String, Map<String, Integer>>> res = new ArrayList<>();
        List<Map<String, Integer>> nowOcupy = new ArrayList<>();
        Map<String, List<String>> edgeToClient = new HashMap<>();
        //第一次粗分配
        for(int i = 0; i < demand.size(); i++){
            Map<String, Integer> demandMap = demand.get(i);
            Iterator<Map.Entry<String, Integer>> it = demandMap.entrySet().iterator();
            Map<String, Integer> siteBandwidthNow = new HashMap<>(siteBandwidth);

            Map<String ,Map<String, Integer>> mapppp = new HashMap<>();
            while (it.hasNext()) {
                int freeSpace = 0;
                Map.Entry<String, Integer> entry = it.next();

                String clientIdPerson = entry.getKey();
                Integer bandwidthNeed = entry.getValue();
                Map<String, Integer> map = new HashMap<>();
                //System.out.println(clientIdPerson);

                if(bandwidthNeed == 0){
                    mapppp.put(clientIdPerson, map);
                    continue;
                }

                List<String> isValuedEdgeNode = new ArrayList<>();
                for(String edgeNodeIdPerson : edgeNodeId){
                    if(qos.get(clientIdPerson + edgeNodeIdPerson) <= qosConStraint){
                        edgeToClient.getOrDefault(edgeNodeIdPerson, new ArrayList<>()).add(clientIdPerson);
                    }
                }

                for(String edgeNodeIdPerson : edgeNodeId){
                    if(qos.get(clientIdPerson + edgeNodeIdPerson) <= qosConStraint && siteBandwidthNow.get(edgeNodeIdPerson) > 0 ){
                        isValuedEdgeNode.add(edgeNodeIdPerson);
                    }
                }
                if(isValuedEdgeNode.size() == 0){
                    notOcupy.put(clientIdPerson, bandwidthNeed);
                }
                for(String en : isValuedEdgeNode){
                    freeSpace += siteBandwidthNow.get(en);
                }
                int nowUsed = 0;

                for(int j = 0; j < isValuedEdgeNode.size() - 1; j++){

                    String edgeIdp = isValuedEdgeNode.get(j);
                    int siteBandwidthNowPerson = siteBandwidthNow.get(edgeIdp);
                    BigInteger tmp = new BigInteger(String.valueOf(bandwidthNeed));
                    tmp = tmp.multiply(BigInteger.valueOf(siteBandwidthNowPerson));
                    int nowPut = tmp.divide(BigInteger.valueOf(freeSpace)).intValue();
                    nowUsed += nowPut;
                    map.put(edgeIdp, nowPut);

                    //System.out.println(edgeIdp + " " + nowPut);
                    siteBandwidthNow.put(edgeIdp, siteBandwidthNow.get(edgeIdp) - nowPut);
                    //System.out.println(clientIdPerson + " " + edgeIdp + " " + siteBandwidthNow.get(edgeIdp));
                }
                int nowFree = bandwidthNeed - nowUsed;
                map.put(isValuedEdgeNode.get(isValuedEdgeNode.size() - 1), nowFree);
                siteBandwidthNow.put(isValuedEdgeNode.get(isValuedEdgeNode.size() - 1), siteBandwidth.get(isValuedEdgeNode.get(isValuedEdgeNode.size() - 1)) - nowFree);
                mapppp.put(clientIdPerson, map);

                //MyFileWriter.WriteStringToFile2(clientIdPerson, urlOut, map);

            }
            res.add(mapppp);
            nowOcupy.add(siteBandwidthNow);
        }
        //MyFileWriter.WriteStringToFile2(res, urlOut);

        //第二步循环做调整
        for(int i = 0; i < demand.size(); i++){
            Map<String, Map<String, Integer>> mapp = res.get(i);
            Map<String, Integer> nowFree = nowOcupy.get(i);
            Map<String, Integer> demandOne = demand.get(i);
            for (int aaa = 1; aaa < 10000; aaa++) {
                for (Map.Entry<String, Integer> entry : nowFree.entrySet()) {
                    String edgeName = entry.getKey();
                    Integer edgeFree = entry.getValue();
                    if(edgeFree < 0){ //此处一定有一个client是大于edgeFree的绝对值的
                        List<String> clients = edgeToClient.get(edgeName);
                        for(String client : clients){
                            Map<String, Integer> fenpeifangan = mapp.get(client);
                            Integer ocupyNum = fenpeifangan.get(edgeName);
                            if(ocupyNum < -edgeFree) continue;

                            nowFree.put(edgeName, edgeFree + ocupyNum);
                            Integer bandwidthNeed = demandOne.get(client) - ocupyNum;
                            List<String> isValuedEdgeNode = new ArrayList<>();

                            for(String edgeNodeIdPerson : edgeNodeId){
                                if(qos.get(client + edgeNodeIdPerson) <= qosConStraint && nowFree.get(edgeNodeIdPerson) > siteBandwidth.get(edgeName) / 10 ){
                                    isValuedEdgeNode.add(edgeNodeIdPerson);
                                }
                            }
                            fenpei(client, bandwidthNeed, fenpeifangan, isValuedEdgeNode, nowFree);
                            break;
                        }
                    }
                }
                for (Map.Entry<String, Integer> entry : notOcupy.entrySet()) {
                    String clientName = entry.getKey();
                    Integer clientNeedSpace = entry.getValue();
                    List<String> isValuedEdgeNode = new ArrayList<>();

                    for(String edgeNodeIdPerson : edgeNodeId){
                        if(qos.get(clientName + edgeNodeIdPerson) <= qosConStraint && nowFree.get(edgeNodeIdPerson) > 0 ){
                            isValuedEdgeNode.add(edgeNodeIdPerson);
                        }
                    }
                    for(int j = 0; j < isValuedEdgeNode.size() - 1; j++){
                        String edgeIdp = isValuedEdgeNode.get(j);
                        int space = nowFree.get(edgeIdp);
                        if(space >= clientNeedSpace){
                            nowFree.put(edgeIdp, space - clientNeedSpace);
                            notOcupy.remove(clientName);
                            break;
                        }
                        clientNeedSpace -= space;
                        nowFree.put(edgeIdp, 0);
                    }

                }
            }


        }


        MyFileWriter.WriteStringToFile2(res, urlOut);

    }

    private static void fenpei(String client, Integer bandwidthNeed, Map<String, Integer> fenpeifangan, List<String> isValuedEdgeNode, Map<String, Integer> nowFree){
        if(isValuedEdgeNode.size() == 0){
            notOcupy.put(client, bandwidthNeed);
        }
        int freeSpace = 0;
        for(String en : isValuedEdgeNode){
            freeSpace += nowFree.get(en);
        }
        int nowUsed = 0;

        for(int j = 0; j < isValuedEdgeNode.size() - 1; j++){

            String edgeIdp = isValuedEdgeNode.get(j);
            int siteBandwidthNowPerson = nowFree.get(edgeIdp);
            BigInteger tmp = new BigInteger(String.valueOf(bandwidthNeed));
            tmp = tmp.multiply(BigInteger.valueOf(siteBandwidthNowPerson));
            int nowPut = tmp.divide(BigInteger.valueOf(freeSpace)).intValue();
            nowUsed += nowPut;
            fenpeifangan.put(edgeIdp, nowPut);
            nowFree.put(edgeIdp, nowFree.get(edgeIdp) - nowPut);
        }
        int nowFreeSpace = bandwidthNeed - nowUsed;
        fenpeifangan.put(isValuedEdgeNode.get(isValuedEdgeNode.size() - 1), nowFreeSpace);
        nowFree.put(isValuedEdgeNode.get(isValuedEdgeNode.size() - 1), nowFree.get(isValuedEdgeNode.get(isValuedEdgeNode.size() - 1)) - nowFreeSpace);
    }
}
